#include "mainloader.h"

MainLoader::MainLoader(){
	MainMap.setSize(5);
	MainMap.parseInput("map_db.txt");
	MainMap.genDirection();
	cout<<"StartPoint : "<<MainMap.getStartPoint().first<<endl;
}

MainLoader::~MainLoader(){

}

MainLoader::MainLoader(const MainLoader& L){
	MainMap = L.MainMap;
}

void MainLoader::ParseEnemy(string S){
	ifstream input;
	input.open(S.c_str());
	if(!input){
		cout<<"File open error"<<endl;
	}else{
		string _name;
		string _url;
		int _hp;
		int _type;
		int _cost;

		while(!input.eof()){
			input>>_name>>_url>>_hp>>_type>>_cost;
			Enemy E(_name,_url,_hp,_type,_cost);
			ListEnemy.push_back(E);
		}
	}
	input.close();
}

void MainLoader::ParseTower(string S){
	ifstream input;
	input.open(S.c_str());
	if(!input){
		cout<<"File open error"<<endl;
	}else{
		string _name;
		string _url;
		int _type;
		int _att;
		int _range;
		int _cost;
		int _isbase;
		int _upgradable;

		while(!input.eof()){
			input>>_name>>_url>>_type>>_att>>_range>>_cost>>_isbase>>_upgradable;
			Tower T(_name,_url,_type,_att,_range,_cost,_isbase,_upgradable);
			ListTower.push_back(T);
		}

	}
	input.close();
}

void MainLoader::PrintListEnemy(){
	int i = 0;
	while(i<ListEnemy.size()){
		string _name = ListEnemy[i].getName();
		string _url = ListEnemy[i].getURL();
		int _hp = ListEnemy[i].getHP();
		int _type = ListEnemy[i].getType();
		int _cost = ListEnemy[i].getCost();
		cout<<i<<". "<<_name<<" "<<_url<<" "<<_hp<<" "<<_type<<" "<<_cost<<endl;
		i++;
	}
}

void MainLoader::PrintInQueueEnemy(){
	int i = 0;
	while(i<InQueueEnemy.size()){
		string _name = InQueueEnemy[i].getName();
		string _url = InQueueEnemy[i].getURL();
		int _hp = InQueueEnemy[i].getHP();
		int _type = InQueueEnemy[i].getType();
		int _cost = InQueueEnemy[i].getCost();
		cout<<i<<". "<<_name<<" "<<_url<<" "<<_hp<<" "<<_type<<" "<<_cost<<endl;
		i++;
	}
}

void MainLoader::PrintInGameEnemy(){
	int i = 0;
	while(i<InGameEnemy.size()){
		string _name = InGameEnemy[i].getName();
		string _url = InGameEnemy[i].getURL();
		int _hp = InGameEnemy[i].getHP();
		int _type = InGameEnemy[i].getType();
		int _cost = InGameEnemy[i].getCost();
		int _posx = InGameEnemy[i].getPosX();
		int _posy = InGameEnemy[i].getPosY();
		cout<<i<<". "<<_name<<" "<<_url<<" "<<_hp<<" "<<_type<<" "<<_cost<<" "<<_posx<<" "<<_posy<<endl;
		i++;
	}
}
void MainLoader::PrintListTower(){
	int i = 0;
	while(i<ListTower.size()){
		string _name = ListTower[i].getName();
		string _url = ListTower[i].getURL();
		int _type = ListTower[i].getType();
		int _att = ListTower[i].getAtt();
		int _range = ListTower[i].getRange();
		int _cost = ListTower[i].getCost();
		int _isbase = ListTower[i].getIsBase();
		int _upgradable = ListTower[i].getUpgradable();
		cout<<i<<". "<<_name<<" "<<_url<<" "<<_type<<" "<<_att<<" "<<_range<<" "<<_cost<<" "<<_isbase<<" "<<_upgradable<<" "<<endl;
		i++;
	}
}

void MainLoader::PrintInGameTower(){
	int i = 0;
	while(i<InGameTower.size()){
		string _name = InGameTower[i].getName();
		string _url = InGameTower[i].getURL();
		int _type = InGameTower[i].getType();
		int _att = InGameTower[i].getAtt();
		int _range = InGameTower[i].getRange();
		int _cost = InGameTower[i].getCost();
		int _isbase = InGameTower[i].getIsBase();
		int _upgradable = InGameTower[i].getUpgradable();
		int _posx = InGameTower[i].getPosX();
		int _posy = InGameTower[i].getPosY();
		cout<<i<<". "<<_name<<" "<<_url<<" "<<_type<<" "<<_att<<" "<<_range<<" "<<_cost<<" "<<_isbase<<" "<<_upgradable<<" "<<_posx<<" "<<_posy<<endl;
		i++;
	}
}

Tower MainLoader::GetTowerFromList(string S){
	int i = 0;
	bool found=false;
	while((i<ListTower.size())&&(!found)){
		if(ListTower[i].getName()==S){
			found=true;
		}else{
			i++;
		}
	}
	return ListTower[i];
}

Tower MainLoader::GetUpgradedTower(string S){
	int i = 0;
	bool found=false;
	while((i<ListTower.size())&&(!found)){
		if(ListTower[i].getName()==S){
			found=true;
		}else{
			i++;
		}
	}
	return ListTower[i+1];
}

Enemy MainLoader::GetEnemyFromList(string S){
	int i = 0;
	bool found=false;
	while((i<ListEnemy.size())&&(!found)){
		if(ListEnemy[i].getName()==S){
			found=true;
		}else{
			i++;
		}
	}
	return ListEnemy[i];
}

void MainLoader::PlantTower(Tower T, int i, int j){
	int n = 0;
	bool found = false;
	while((n<ListTower.size()) && (!found)){
		if((ListTower[n].getPosX()==MainMap.gridPos(i,j).first)&&(ListTower[n].getPosY()==MainMap.gridPos(i,j).second)){
			found = true;
		}else{
			n++;
		}
	}
	if(!found){
		T.setPosX(MainMap.gridPos(i,j).first);
		T.setPosY(MainMap.gridPos(i,j).second);
		InGameTower.push_back(T);
	}
}

void MainLoader::RemoveTower(Tower T){
	int i = 0;
	bool found = false;
	while((i<InGameTower.size())&&(!found)){
		if((T.getPosX()==InGameTower[i].getPosX())&&(T.getPosY()==InGameTower[i].getPosY())){
			found = true;
		}else{
			i++;
		}
	}
	InGameTower.erase(InGameTower.begin()+i);
}

void MainLoader::UpgradeTower(Tower T){
	cout<<T.getName()<<endl;
	if(T.getUpgradable()==1){
		Tower newT = GetUpgradedTower(T.getName());
		cout<<newT.getName()<<endl;
		newT.setPosX(T.getPosX());
		newT.setPosY(T.getPosY());
		int gridx = MainMap.whichGrid(newT.getPosX(),newT.getPosY()).first;
		int gridy = MainMap.whichGrid(newT.getPosX(),newT.getPosY()).second;
		RemoveTower(T);
		PlantTower(newT,gridx,gridy);
	}
}

void MainLoader::AddQueueingEnemy(Enemy E){
	InQueueEnemy.push_back(E);
}

void MainLoader::DeployEnemy(){
	Enemy E = InQueueEnemy.back();
	InQueueEnemy.pop_back();
	int x = MainMap.getStartPoint().first;
	int y = MainMap.getStartPoint().second;
	E.setPosX(MainMap.gridPos(x,y).first);
	E.setPosY(MainMap.gridPos(x,y).second);
	InGameEnemy.push_back(E);
}

Tower MainLoader::EditTowerInGame(int x,int y){
	int i = 0;
	bool found=false;
	Tower T("","",0,0,0,0,0,0);
	while ((i<InGameTower.size())&&(!found)){
		int gridx = MainMap.gridPos(x,y).first;
		int gridy = MainMap.gridPos(x,y).second;
		if((InGameTower[i].getPosX()==gridx)&&(InGameTower[i].getPosY()==gridy)){
			T = InGameTower[i];
			found = true;
		}else{
			i++;
		}
	}
	return T;
}

int MainLoader::GetMaxCostEnemy(){
	int temp = 0;
	int i = 0;
	while(i<ListEnemy.size()){
		if(ListEnemy[i].getCost()>=temp){
			temp = ListEnemy[i].getCost();
		}
		i++;
	}
	return temp;
}

int MainLoader::GetMaxCostTower(){
	int temp = 0;
	int i = 0;
	while(i<ListTower.size()){
		if(ListTower[i].getCost()>=temp){
			temp = ListTower[i].getCost();
		}
		i++;
	}
	return temp;
}

int MainLoader::GetMinCostEnemy(){	
	int i = 1;
	int temp = ListEnemy[0].getCost();
	while(i<ListEnemy.size()){
		if(ListEnemy[i].getCost()<=temp){
			temp = ListEnemy[i].getCost();
		}
		i++;
	}
	return temp;
}

int MainLoader::GetMinCostTower(){	
	int i = 1;
	int temp = ListTower[0].getCost();
	while(i<ListTower.size()){
		if(ListTower[i].getCost()<=temp){
			temp = ListTower[i].getCost();
		}
		i++;
	}
	return temp;
}

int MainLoader::GetMaxBelowCostEnemy(int cost){
	int temp = 0;
	int i = 0;
	while(i<ListEnemy.size()){
		if((ListEnemy[i].getCost()>=temp)&&(ListEnemy[i].getCost()<cost)){
			temp = ListEnemy[i].getCost();
		}
		i++;
	}
	return temp;
}

int MainLoader::GetMaxBelowCostTower(int cost){
	int temp = 0;
	int i = 0;
	while(i<ListTower.size()){
		if((ListTower[i].getCost()>=temp)&&(ListTower[i].getCost()<cost)){
			temp = ListTower[i].getCost();
		}
		i++;
	}
	return temp;
}

int MainLoader::GetMinAboveCostEnemy(int cost){
	int i = 1;
	int temp = 99999;
	while(i<ListEnemy.size()){
		if((ListEnemy[i].getCost()<=temp)&&(ListEnemy[i].getCost()>cost)){
			temp = ListEnemy[i].getCost();
		}
		i++;
	}
	return temp;
}

int MainLoader::GetMinAboveCostTower(int cost){
	int temp = 99999;
	int i = 1;
	while(i<ListTower.size()){
		if((ListTower[i].getCost()<=temp)&&(ListTower[i].getCost()>cost)){
			temp = ListTower[i].getCost();
		}
		i++;
	}
	return temp;
}

vector<Enemy> MainLoader::GetInGameEnemy(int){
	vector<Enemy> V;
	for(int i=0;i<InGameEnemy.size();i++){
		V.push_back(InGameEnemy[i]);
	}
	return V;
}

vector<Enemy> MainLoader::ListEnemyByCost(int cost){
	vector<Enemy> V;
	int i = 0;
	while(i<ListEnemy.size()){
		if(ListEnemy[i].getCost()==cost){
			V.push_back(ListEnemy[i]);
		}
		i++;
	}
	return V;	
}

vector<Tower> MainLoader::ListTowerByCost(int cost){
	vector<Tower> V;
	int i = 0;
	while(i<ListTower.size()){
		if(ListTower[i].getCost()==cost){
			V.push_back(ListTower[i]);
		}
		i++;
	}
	return V;
}

vector<Tower> MainLoader::ListBaseTower(){
	vector<Tower> V;
	int i = 0;
	while(i<ListTower.size()){
		if(ListTower[i].getIsBase()==1){
			V.push_back(ListTower[i]);
		}
		i++;
	}
	return V;
}

bool MainLoader::IsSpaceOccupied(int x, int y){
	int posgridx = MainMap.gridPos(x,y).first;
	int posgridy = MainMap.gridPos(x,y).second;
	int i = 0;
	bool found = false;
	while((i<InGameTower.size())&&(!found)){
		if((InGameTower[i].getPosX()==posgridx)&&(InGameTower[i].getPosY()==posgridy)){
			found = true;
		}else{
			i++;
		}
	}
	return found;
}

pair<int,int> MainLoader::GetTowerBestPlaceAvail(){
	int temp = 0;
	int gridx = -1;
	int gridy = -1;
	for(int i=0;i<MainMap.getSize();i++){
		for(int j=0;j<MainMap.getSize();j++){
			if(MainMap.getBobot(i,j)>temp){
				if(!IsSpaceOccupied(i,j)){
					gridx = i;
					gridy = j;
					temp = MainMap.getBobot(i,j);
				}
			}
		}
	}
	return (make_pair(gridx,gridy));
}

pair<int,int> MainLoader::GetTowerBestPlace(){
	int temp = 0;
	int gridx = -1;
	int gridy = -1;
	for(int i=0;i<MainMap.getSize();i++){
		for(int j=0;j<MainMap.getSize();j++){
			if(MainMap.getBobot(i,j)>temp){
				gridx = i;
				gridy = j;
				temp = MainMap.getBobot(i,j);
			}
		}
	}
	return (make_pair(gridx,gridy));
}

vector<Enemy> MainLoader::CreateWaveByMaxCost(int cost){
	int tempcost=0;
	vector<Enemy> tempwave;
	vector <Enemy> temp;
	bool flag = false;
	int tempmax = GetMaxCostEnemy();
	int randomize=0;
	srand(time(NULL));
	while((tempcost<cost)&&(!flag)){
		temp = ListEnemyByCost(tempmax);
		while(tempcost+tempmax<=cost){
			if(temp.size()>1){
				randomize = rand() % temp.size();
				cout<<"Random number : "<<randomize<<endl;
			}
			tempwave.push_back(temp[randomize]);
			tempcost = tempcost+tempmax;
		}
		tempmax = GetMaxBelowCostEnemy(tempmax);
		if(tempmax==0){flag = true;}
	}
	for(int i=0;i<tempwave.size();i++){
		cout<<tempwave[i].getName()<<endl;
	}
	InQueueEnemy = tempwave;
	return tempwave;
}

vector<Enemy> MainLoader::CreateWaveByMinCost(int cost){
	int tempcost=0;
	vector<Enemy> tempwave;
	vector <Enemy> temp;
	bool flag = false;
	int tempmin = GetMinCostEnemy();
	int randomize=0;
	srand(time(NULL));
	while((tempcost<cost)&&(!flag)){
		temp = ListEnemyByCost(tempmin);
		while(tempcost+tempmin<=cost){
			if(temp.size()>1){
				randomize = rand() % temp.size();
				cout<<"Random number : "<<randomize<<endl;
			}
			tempwave.push_back(temp[randomize]);
			tempcost = tempcost+tempmin;
		}
		tempmin = GetMinAboveCostEnemy(tempmin);
		if(tempmin==99999){flag = true;}
	}
	for(int i=0;i<tempwave.size();i++){
		cout<<tempwave[i].getName()<<endl;
	}
	InQueueEnemy = tempwave;
	return tempwave;
}

void MainLoader::GreedyTowerByCost(int cost){	
	bool flag=true;
	srand(time(NULL));
	while(flag==true){
		int i = 0;
		bool flag1=false;
		bool flag2=false;		
		while((i<InGameTower.size())&&(cost>=0)){
			if(InGameTower[i].getUpgradable()==1){
				if(cost-GetUpgradedTower(InGameTower[i].getName()).getCost()>=0){
					cost=cost-GetUpgradedTower(InGameTower[i].getName()).getCost();
					cout<<"Upgrade Tower "<<InGameTower[i].getName()<<endl;
					UpgradeTower(InGameTower[i]);
					flag1=true;
				}else{
					i++;
				}
			}else{
				i++;
			}
		}
		vector<Tower> V = ListBaseTower();//sermua base tower punya cost sama
		//int randomize;
		//srand(time(NULL));		
		if(cost>=0){
			int randomize = rand() % V.size();
			cout<<"Random number : "<<randomize<<endl;
			Tower T = V[randomize];
			if(cost-T.getCost()>=0){
				cost = cost-T.getCost();
				cout<<"Plant Tower "<<T.getName()<<endl;
				PlantTower(T,GetTowerBestPlaceAvail().first,GetTowerBestPlaceAvail().second);
				flag2=true;
			}
		}
		flag = ((flag1)||(flag2));
	}
	cout<<"Done"<<endl;
}